import * as obvm from '../../jsruntime/runtime/vm.mjs'
class ProxyFSM {
    constructor(client,sceneId) {
        this.client = client;
        this.sceneId = sceneId;
        this.listenMessageTitleAndHandle = new Map();
    }
    PostMessage(msg) {
        let cmd = {
            cmd: 'CSNetwork-serverToClientMsg',
            arg: {
                sceneId: this.sceneId,
                vmID: msg.sender.VM.id,
                fsmID: msg.sender.id,
                msg: {
                    arg: msg.arg,
                    argType: msg.argType,
                    name: msg.name
                }
            }
        };
        this.client.postMessage(cmd, '*');
    }
}
export default class VirtualServer {
    static install(script) {
        let server = new VirtualServer();
        script.InstallLib("CSNetwork-Server", "CSNetwork-Server", [
            script.NativeUtil.closureVoid(server.acceptClientConnection.bind(server), [], true),
            script.NativeUtil.closureVoid(server.stopAcceptingClientConnection.bind(server), [], true),
            script.NativeUtil.closureVoid(server.acceptClientMessage.bind(server), ['NObjectRegister', 'StringRegister'], true),
            script.NativeUtil.closureVoid(server.stopAcceptingClientMessage.bind(server), ['NObjectRegister', 'StringRegister'], true),
        ]);
    }
    constructor() {
        this.connnected = new Map();
        this.listenerFSM = null;
        this.messageHandler = this.messageHandler.bind(this);
        this.onVMDestoryed = this.onVMDestoryed.bind(this);
    }
    messageHandler(event) {
        let cmd = event.data.cmd;
        if (!cmd) {
            return;
        }
        let arg = event.data.arg;
        switch (cmd) {
            case 'CSNetwork-connectToSerever':
                if (!this.listenerFSM) {
                    return;
                }
                if (arg?.sceneId == this.scene?.id) {
                    // clientWindow -> {connections:allCon}
                    // allCon:clientWindow->proxyFSM
                    let proxyFSM = this.connnected.get(event.source);
                    if (!proxyFSM) {
                        proxyFSM = new ProxyFSM(event.source,this.scene.id);
                        this.connnected.set(event.source, proxyFSM);
                        this.listenerFSM.PostMessage(this.vm.buildEventMessage('clientConnected', "CSNetwork_connection", proxyFSM));
                    }
                    let cmd = {
                        cmd: 'CSNetwork-serverConnected',
                        arg
                    }
                    event.source.postMessage(cmd, '*');
                }
                break;
            case 'CSNetwork-clientToServerMsg':
                if (arg?.sceneId == this.scene?.id) {
                    let proxyFSM = this.connnected.get(event.source);
                    if (!proxyFSM) {
                        return;
                    }
                    let fsmList = proxyFSM.listenMessageTitleAndHandle.get(arg.msg.name);
                    if (fsmList) {
                        let msg = this.vm.buildUsertMessage(arg.msg.name, arg.msg.argType, arg.msg.arg, proxyFSM);
                        fsmList.forEach(fsm => {
                            fsm.PostMessage(msg);
                        });
                    }
                }
                break;
        }
    }
    onVMDestoryed() {
        this.vm.removeEventListener('Destory', this.onVMDestoryed);
        window.removeEventListener('message', this.messageHandler);
    }
    acceptClientConnection(st) {
        this.vm = st.fsm.VM;
        this.scene = this.vm.__scene;
        this.listenerFSM = st.fsm;
        this.vm.addEventListener('Destroy', this.onVMDestoryed);
        window.addEventListener('message', this.messageHandler, false)
    }
    stopAcceptingClientConnection() {
        this.listenerFSM = null;
        window.removeEventListener('message', this.messageHandler);
    }
    acceptClientMessage(proxyFSM, title, st, of) {
        if (!proxyFSM) {
            console.warn('未指定 proxyFSM');
            st.fsm.VM.Log('未指定 proxyFSM', 'sys', 4, st, of);
            return;
        }
        if (typeof (title) != 'string') {
            console.warn('监听消息标题不是字符串类型 ' + title + '(' + typeof (title) + ')');
            st.fsm.VM.Log('未指定 proxyFSM', 'sys', 8, st, of);
            return;
        }
        let fsmList = proxyFSM.listenMessageTitleAndHandle.get(title);
        if (!fsmList) {
            fsmList = [];
            proxyFSM.listenMessageTitleAndHandle.set(title, fsmList);
        } else if (fsmList.indexOf(st.fsm) >= 0) {
            return;
        }
        fsmList.push(st.fsm);
    }
    stopAcceptingClientMessage(proxyFSM, title, st) {
        if (!proxyFSM) {
            console.warn('未指定 proxyFSM');
            st.fsm.VM.Log('未指定 proxyFSM', 'sys', 4, st, of);
            return;
        }
        if (typeof (title) != 'string') {
            console.warn('监听消息标题不是字符串类型 ' + title + '(' + typeof (title) + ')');
            st.fsm.VM.Log('未指定 proxyFSM', 'sys', 8, st, of);
            return;
        }
        let fsmList = proxyFSM.listenMessageTitleAndHandle.get(title);
        let idx = fsmList.indexOf(st.fsm);
        if (idx >= 0) {
            fsmList.splice(idx, 1);
        }
    }
}